Skip to content

Fix 500 when editing an event whose course is in another organization - #2234

Closed
moveson wants to merge 1 commit into
masterfrom
oveson/claude/event-form-foreign-course-500
Closed

Fix 500 when editing an event whose course is in another organization#2234
moveson wants to merge 1 commit into
masterfrom
oveson/claude/event-form-foreign-course-500

Conversation

@moveson

@moveson moveson commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the staging 500 hit while testing #2233 (Scout error group 124190 on ost-staging: ArgumentError: change_event_course must include new_course from PATCH /event_groups/2023-marathon-test/events/2023-marathon-test-100k).

The bug predates the projections work — the new checkbox was just the first reason anyone submitted the edit form for that event. The chain:

  1. EventSetupPresenter#courses_for_select offers only the event group organization's courses, and this event's course belongs to a different organization, so the selector had no option matching the event's course_id and booted showing "Create a new course" (value blank).
  2. The event-setup Stimulus controller syncs the selector into the hidden course_id field on connect, blanking it before the user touches anything.
  3. On submit, course_id is blank, conform_changed_course fires as a before_validation — ahead of the belongs_to :course presence validation — and ChangeEventCourse.perform! raises.

Two-layer fix:

  • Form: courses_for_select now prepends the event's own course when it is missing from the organization's list, so the selector always reflects reality and the hidden field is never silently blanked.
  • Model: conform_changed_course returns early when course is nil, letting the presence validation reject the record with a normal 422 re-render instead of a 500 — covering any other path that blanks course_id.

Testing

  • New EventSetupPresenter spec: options include the event's cross-organization course (fails pre-fix); ordinary org courses still listed with the create-new option first.
  • New Event spec: clearing course_id on a persisted event is invalid with "must exist" rather than raising (fails pre-fix).
  • Wider suites green: event model, all presenters, edit event flow system spec — 178 examples, 0 failures.
  • rubocop clean on touched files.

🤖 Generated with Claude Code

The event form's course selector only offered the event group
organization's courses. An event whose course belongs to a different
organization booted the selector to "Create a new course", the setup
Stimulus controller copied that blank value into the hidden course_id
field, and submitting raised ArgumentError in ChangeEventCourse (a 500)
because conform_changed_course runs before_validation, ahead of the
belongs_to presence check.

Include the event's own course in the selector options when it is
missing from the organization's list, and bail out of the course-change
conforming when the course is blank so the presence validation returns
a normal 422 instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@moveson

moveson commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Closing unmerged in favor of fixing the data. The production audit (#2235) found zero cross-organization events, so this 500 cannot occur against production data — the failing case was a staging-only relic from the era when courses had no organization owner, and those rows are being repaired per the remediation plan on #2235.

The two useful ideas here move to the follow-up hardening PR proposed on #2235:

  • a validation that an event's course belongs to its event group's organization (prevents new relics from any path, including imports and DuplicateEventGroup)
  • the model-level guard from this PR (conform_changed_course bailing on a blank course so a nil course_id — e.g. an API PATCH with course_id: null — returns a 422 instead of a 500)

The form-side courses_for_select change is dropped entirely: it existed only to accommodate data that should not exist.

@moveson moveson closed this Aug 21, 2026
@moveson
moveson deleted the oveson/claude/event-form-foreign-course-500 branch August 21, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant